Matching the bouy data to the other data collected

hilo <- hbb_wku_h_xts
hilo <- data.frame(date=index(hilo), coredata(hilo))
hilo <- hilo[529:54816,]
hilo
# which(hilo$date=="2010-10-23 00:00:00") = index 529 

# which(hilo$date=="2016-12-31 23:00:00") = index 54816
length(hilo[,1]) # we are left with 54288 lines of data
[1] 54288
54816 - length(hilo[,1]) # we lost 528 values 
[1] 528

Changing column names

# removing columns that we are not using 
hilo$date.2 <- NULL # another date column
hilo$date.1 <- NULL # another date column
hilo$BGARFU <- NULL # ?
hilo$cfs <- NULL
hilo$DOmgL <- NULL # dissolved oxygen
#hilo$Doper <- NULL # dissolved oxygen
hilo$PAR1 <- NULL # ?
hilo$pH <- NULL # pH
hilo$NTU <- NULL # a different measurement for turbitity
hilo$DOper10 <- NULL # dissolved oxygen

# colnames(hilo) <- c("Date", "cfs", "RiverFlow-cumec", "LogRiverFlow-cumec", "Chlorophyll-RFU", "Salinity-PPT", "Temp-C", "chlorophyll-calibrator", "Turbidity-NTU")
# does not work ???

hilo

====================================================

FULL DATA SET 2012-2016

Descriptives: PLots

River Flow FULL DATA SET

length(hilo$logcms[which(is.na(hilo$logcms)==TRUE)]) # 12 NAs 
[1] 12
which(is.na(hilo$logcms)==TRUE)
 [1] 50509 50510 50511 50512 50513 50514 50515 50516 50517 50518 50519 50520
RiverFlow <- ggplot(hilo,  aes(x = date, y = as.numeric(cms))) + 
  geom_line()

print(RiverFlow + ggtitle("River Flow")+labs(x="Time", y = "River Flow - cubic meters per second"))

CHL FULL DATA SET

length(hilo$ChlRFU[which(is.na(hilo$ChlRFU)==TRUE)]) # 20464 NAs

which(as.numeric(hilo$ChlRFU)==max(as.numeric(na.omit(hilo$ChlRFU)))) # 15.3 max 
# CHL tells us where in the data set this happened  
hilo[38974,]

CHL <- ggplot(hilo,  aes(x = date, y = as.numeric(ChlRFU))) + 
  geom_line()

print(CHL + ggtitle("Chlorophyll ")+labs(x="Time", y = "Chlorophyll  - relative fluorescence units (RFU)"))

Turbity FULL DATA SET

length(hilo$Corr.NTU[which(is.na(hilo$Corr.NTU)==TRUE)]) #15012 NAs

which(as.numeric(hilo$Corr.NTU)==max(as.numeric(na.omit(hilo$Corr.NTU)))) # 88.4
# tells us where in the data set this happened
hilo[33243,]

TURB <- ggplot(hilo,aes(x = date, y = as.numeric(Corr.NTU))) + 
  geom_line()

print(TURB + ggtitle("Turbidity ")+labs(x="Time", y = "Turbidity - Nephelometric Turbidity Units (NTU)"))

Salinity FULL DATA SET

length(hilo$saltppt[which(is.na(hilo$saltppt)==TRUE)]) #11330 NAs

SALT <- ggplot(hilo,  aes(x = date, y = as.numeric(saltppt))) + 
  geom_line()

print(SALT + ggtitle("Salinity")+labs(x="Time", y = "Salinity - unit parts per thousand (PPT)"))

======================================================== # Histograms FULL DATA SET ## River Flow Histogram

hist(as.numeric(hilo$logcms), main = "Histogram of Log River Flow", xlab = "Log River Flow")

# this looks okay

CHL Histogram

# VERY skewed
hist(as.numeric(hilo$ChlRFU), main = "Histogram of Chlorophyll", xlab = "Chlorophyll  - relative fluorescence units (RFU)")

# this looks better
hist(log(as.numeric(hilo$ChlRFU)), main = "Histogram of Log Chlorophyll", xlab = "Chlorophyll")
# not sure what happens to units when taking the log 

Turbity Histogram

# VERY skewed
hist(as.numeric(hilo$Corr.NTU), main = "Histogram of Turbidity", xlab = "Turbidity - Nephelometric Turbidity Units (NTU)")

# this looks better
hist(log(as.numeric(hilo$Corr.NTU)), main = "Histogram of Log Turbidity", xlab = "Turbidity")
# not sure what happens to units when taking the log 

Salinity Histogram

# skewed
hist(as.numeric(hilo$saltppt), main = "Histogram of Salinity", xlab = "Salinity - unit parts per thousand (PPT)")

# this is worst!
hist(log(as.numeric(hilo$saltppt)), main = "Histogram of Log Salinity", xlab = "Salinity")
# not sure what happens to units when taking the log 

========================================================= # NEW DATA SET-Modified Data 2013-2015

# start date: 2013-01-01 00:00:00
# end date: 2015-12-31 23:00:00
hilomodified <- hilo[19225:45504,]
length(hilo[,1])-length(hilomodified[,1])
[1] 28008
# lost 28008 entries of data 

length(hilomodified[,1])-528 # we are left with 25752 entries of data 
[1] 25752
head(hilomodified)
tail(hilomodified)
NA

Descriptives on all variables MODIFIED DATA SET: Using Favstats

River Flow Favstats

library(mosaic)
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
Registered S3 method overwritten by 'mosaic':
  method                           from   
  fortify.SpatialPolygonsDataFrame ggplot2

The 'mosaic' package masks several functions from core packages in order to add 
additional features.  The original behavior of these functions should not be affected by this.

Attaching package: ‘mosaic’

The following object is masked from ‘package:Matrix’:

    mean

The following object is masked from ‘package:scales’:

    rescale

The following objects are masked from ‘package:dplyr’:

    count, do, tally

The following object is masked from ‘package:ggplot2’:

    stat

The following objects are masked from ‘package:stats’:

    binom.test, cor, cor.test, cov, fivenum, IQR, median, prop.test, quantile,
    sd, t.test, var

The following objects are masked from ‘package:base’:

    max, mean, min, prod, range, sample, sum
favstats(hilomodified$cms)
Auto-converting character to numeric.

CHL Favstats

favstats(hilomodified$ChlRFU)

Turbitity Favstats

favstats(hilomodified$Corr.NTU)

Salinity Favstats

favstats(hilomodified$saltppt)
favstats(hilomodified$TempC)
favstats(hilomodified$Doper)

===================================================== # MODIFIED DATA SET 2013-2015 # Descriptives: Plots

River Flow MODIFIED

length(hilomodified$logcms[which(is.na(hilomodified$logcms)==TRUE)]) # No NAs, YAY!
[1] 0
which(is.na(hilomodified$logcms)==TRUE)
integer(0)
RiverFlowMod <- ggplot(hilomodified,  aes(x = date, y = as.numeric(cms))) + 
  geom_line()

print(RiverFlowMod + ggtitle("River Flow")+labs(x="Time", y = "River Flow - cubic meters per second"))

CHL MODIFIED

sum(is.na(hilomodified$ChlRFU)==TRUE) # 1884 NAs
[1] 1884
#which(is.na(hilomodified$ChlRFU)==TRUE)
# max(as.numeric(na.omit(hilo$ChlRFU))) # 15.3
which(as.numeric(hilomodified$ChlRFU)==15.3)
[1] 19750
hilo[38974,]

CHLMod <- ggplot(hilomodified,  aes(x = date, y = as.numeric(ChlRFU))) + 
  geom_line()

print(CHLMod + ggtitle("Chlorophyll ")+labs(x="Time", y = "Chlorophyll  - relative fluorescence units (RFU)"))

Turbitity MODIFIED

length(hilomodified$Corr.NTU[which(is.na(hilomodified$Corr.NTU)==TRUE)]) # 2704 NAs
# max(as.numeric(na.omit(hilo$Corr.NTU))) # 88.4
which(as.numeric(hilo$Corr.NTU)==88.4)
hilo[33243,]

TURBMod <- ggplot(hilomodified,  aes(x = date, y = as.numeric(Corr.NTU))) + 
  geom_line()

print(TURBMod + ggtitle("Turbidity ")+labs(x="Time", y = "Turbidity - Nephelometric Turbidity Units (NTU)"))

Salinity MODIFIED

length(hilomodified$saltppt[which(is.na(hilomodified$saltppt)==TRUE)]) # 2267 NAs

SALTMod <- ggplot(hilomodified,  aes(x = date, y = as.numeric(saltppt))) + 
  geom_line()

print(SALTMod + ggtitle("Salinity")+labs(x="Time", y = "Salinity - unit parts per thousand (PPT)"))

Tempurature MODIFIED

length(hilomodified$TempC[which(is.na(hilomodified$TempC)==TRUE)]) # 2267 NAs

TempMod <- ggplot(hilomodified,  aes(x = date, y = as.numeric(TempC))) + 
  geom_line()

print(TempMod + ggtitle("Temperature")+labs(x="Time", y = "Temperature - Celsius"))

Dissolved Oxygen MODIFIED

length(hilomodified$Doper[which(is.na(hilomodified$Doper)==TRUE)]) # 2267 NAs

TempMod <- ggplot(hilomodified,  aes(x = date, y = as.numeric(Doper))) + 
  geom_line()

print(TempMod + ggtitle("Dissolved Oxygen")+labs(x="Time", y = "Dissolved Oxygen in percent of saturation"))

=================================================== # Histograms MODIFIED

River Flow MODIFIED

hist(as.numeric(hilomodified$cms), main = "Histogram of Log River Flow", xlab = "Log River Flow", breaks =90, xlim = c(0,100))

# this looks okay

CHL MODIFIED

# VERY skewed
hist(as.numeric(hilomodified$ChlRFU), main = "Histogram of Chlorophyll", xlab = "Chlorophyll  - relative fluorescence units (RFU)")

# this looks better
hist(log(as.numeric(hilomodified$ChlRFU)), main = "Histogram of Log Chlorophyll", xlab = "Chlorophyll")
# not sure what happens to units when taking the log 

Turbitity MODIFIED

# VERY skewed
hist(as.numeric(hilomodified$Corr.NTU), main = "Histogram of Turbidity", xlab = "Turbidity - Nephelometric Turbidity Units (NTU)")

# this looks better
hist(log(as.numeric(hilomodified$Corr.NTU)), main = "Histogram of Log Turbidity", xlab = "Turbidity")
# not sure what happens to units when taking the log 

Salinity MODIFIED

# skewed
hist(as.numeric(hilomodified$saltppt), main = "Histogram of Salinity", xlab = "Salinity - unit parts per thousand (PPT)")

# this is worst!
hist(log(as.numeric(hilomodified$saltppt)), main = "Histogram of Log Salinity", xlab = "Salinity")
# not sure what happens to units when taking the log 

=============================================================

Plot with ALL Var 2013-2015

It is hard to see what is going on

AllYears <- ggplot(hilomodified,  aes(x = date, y = as.numeric(logcms))) + 
  geom_line()+
  geom_line(aes(y = as.numeric(saltppt)), color = "darkred") +
  geom_line(aes(y = as.numeric(Corr.NTU)), color="darkgreen") +
  geom_line(aes(y=as.numeric(ChlRFU)),color="blue")

print(AllYears + ggtitle("Hilo Bay")+labs(x="Time", y = "River Flow - cubic meters per second"))

============================================================== # Descriptives by Storm We are picking one storm from each year. We can indicate a storm has occurred by the extreme events in the river flow data. We will not use the log (which is logbase10) in order to see the extreme events When salinity is below 35 this also indicates a storm has occurred.

We will break the data set by year to find the most extreme event for each year.

2013 Data & Plot

# max(as.numeric(hilo2013$logcms)) # this is log base 10 
# This is NOT the natural log
max(as.numeric(hilo2013$cms)) # 207.186 
which(as.numeric(hilo2013$cms) == max(as.numeric(hilo2013$cms)))

hilo2013[3550,]
# all values for this storm are NA

plot2013 <- ggplot(hilo2013,  aes(x = date, y = as.numeric(cms))) + 
  geom_line(color="black")+
  geom_line(aes(y = as.numeric(saltppt)), color = "darkred") +
  geom_line(aes(y = as.numeric(Corr.NTU)), color="darkgreen") +
  geom_line(aes(y=as.numeric(ChlRFU)),color="blue")

print(plot2013 + ggtitle("2013")+labs(x="Time", y = "River Flow - cubic meters per second"))

Split 2013 into 6 months to get a better visual

# R2013.1 <- ggplot(hilo2013[1:(length(hilo2013[,1])/2),],  aes(x = date, y = as.numeric(cms))) + 
#   geom_line(color="black")+
#   geom_line(aes(y = as.numeric(saltppt)), color = "darkred") +
#   geom_line(aes(y = as.numeric(Corr.NTU)), color="darkgreen") +
#   geom_line(aes(y=as.numeric(ChlRFU)),color="blue")
# print(R2013.1 + ggtitle("River Flow")+labs(x="Time", y = "River Flow - cubic meters per second"))
# R2013.1+ylim(0,40)
# 
# 
# R2013.2 <- ggplot(hilo2013[(length(hilo2013[,1])/2):length(hilo2013[,1]),],  aes(x = date, y = as.numeric(cms))) + 
#   geom_line(color="black")+
#   geom_line(aes(y = as.numeric(saltppt)), color = "darkred") +
#   geom_line(aes(y = as.numeric(Corr.NTU)), color="darkgreen") +
#   geom_line(aes(y=as.numeric(ChlRFU)),color="blue")
# print(R2013.2 + ggtitle("River Flow")+labs(x="Time", y = "River Flow - cubic meters per second"))
# R2013.2+ylim(0,40)

2014 Data & Plot

# Max river flow in the overall data set
max(as.numeric(hilo2014$cms))
max(as.numeric(hilomodified$cms))

which(as.numeric(hilo2014$cms) == max(as.numeric(hilo2014$cms)))

hilo2014[5263,]

R2014 <- ggplot(hilo2014,  aes(x = date, y = as.numeric(logcms))) + 
  geom_line(color="black")+
  geom_line(aes(y = as.numeric(saltppt)), color = "darkred") +
  geom_line(aes(y = as.numeric(Corr.NTU)), color="darkgreen") +
  geom_line(aes(y=as.numeric(ChlRFU)),color="blue")

print(R2014 + ggtitle("2014")+labs(x="Time", y = "River Flow - cubic meters per second"))

2015 Data & Plot

max(as.numeric(hilo2015$cms))

which(as.numeric(hilo2015$cms) == max(as.numeric(hilo2015$cms)))

hilo2015[6475,]

R2015 <- ggplot(hilo2015,  aes(x = date, y = as.numeric(logcms))) + 
  geom_line(color="black")+
  geom_line(aes(y = as.numeric(saltppt)), color = "darkred") +
  geom_line(aes(y = as.numeric(Corr.NTU)), color="darkgreen") +
  geom_line(aes(y=as.numeric(ChlRFU)),color="blue")

print(R2015 + ggtitle("2015")+labs(x="Time", y = "River Flow - cubic meters per second"))

# Separating the Data by Storm Events

Separating the Data by Storm

outcomes <- as.numeric(hilomodified$saltppt)<25 
index.lt25 <- which(outcomes==TRUE)

poss.storms <- hilomodified[index.lt25,]
poss.storms
outcomes.35 <- as.numeric(hilomodified$saltppt)<35 
index.lt35 <- which(outcomes==TRUE)
index.lt25
poss.storms35 <- hilomodified[index.lt25,]
poss.storms35

hilomodified$date[16]
storm.1.7.13 <- ggplot(hilomodified[145:168,],  aes(x = date, y = as.numeric(cms))) + 
  geom_line(color="black")+
  geom_line(aes(y = as.numeric(saltppt)), color = "lightsteelblue1") +
  geom_line(aes(y = as.numeric(Corr.NTU)), color="grey69") +
  geom_line(aes(y=as.numeric(ChlRFU)),color="khaki")

print(storm.1.7.13 + ggtitle("Storm 1/7/13")+labs(x="Time"))

Trying to make the Rainfall plot easier to read

RiverFlow1 <- ggplot(hilomodified[1:100,],  aes(x = date, y = as.numeric(cms))) + 
  geom_line()

print(RiverFlow + ggtitle("River Flow")+labs(x="Time", y = "River Flow - cubic meters per second"))

=======

getwd()
# write.csv(hilomodified,file="HiloBayNEW13to15.csv", row.names = FALSE)

NEW Change in River Flow Column

# any value greater than or equal to 10 cms indicates a storm
pos.neg <- as.numeric(hilomodified$cms) - 10 

start <- vector()
end <- vector()

for(i in 1:length(pos.neg)){
  if(isTRUE(pos.neg[i] < 0 && pos.neg[i+1] > 0)){ 
    # if goes from + to - then this is the beginning of a storm
    start[i] <- i
  }else if(isTRUE(pos.neg[i] > 0 && pos.neg[i+1] < 0)){
    # if goes from - to + then this is the end of the storm
    end[i] <- i
    }
}
start<-start[!is.na(start)] # removing NA
start
 [1]   141   212   891  1097  1106  3480  3499  3545  5309  7537  8713  8729 10388 10390
[15] 10411 10727 10737 10843 10917 11216 11340 11508 11646 12581 13406 13458 13551 13655
[29] 13866 14010 15233 15287 15722 16054 16727 19777 19802 19920 20066 20386 20622 20662
[43] 21143 21163 22249 22656 22762 22911 23008 23015 23060 23116 23201 23395 23640 23703
[57] 23740 23757 23774 23807 23947 24141 24312 24437 24938 25005 25246 25474 25492 25972
[71] 26107 26187
length(start) # make sure both start and end are the same length 
[1] 72
end<-end[!is.na(end)]
end
 [1]   162   226   903  1102  1398  3495  3500  3572  5338  7547  8718  8765 10389 10404
[15] 10412 10732 10752 10845 11044 11232 11346 11525 11695 12596 13445 13514 13648 13670
[29] 13888 14111 15235 15288 15750 16148 16749 19790 19811 19938 20087 20394 20650 20719
[43] 21153 21169 22257 22675 22771 22972 23013 23020 23070 23130 23215 23403 23670 23719
[57] 23742 23761 23781 23899 24082 24168 24325 24510 24945 25233 25328 25482 25499 26093
[71] 26117 26214
length(end)
[1] 72
library(ggplot2)
for(i in 1:length(start)){
  # the point start[i] is the beginning of a storm
  # the point end[i] is the end of the same storm
  # we are adding 24 hours to each start and end time
 p <- ggplot(hilomodified[(start[i]-24):(end[i]+24),],aes(x = date, y = as.numeric(cms))) +
  geom_line(color="black")
 p <- p + geom_line(aes(y = range01(as.numeric(Corr.NTU))), color="green") 
 p <- p + geom_line(aes(y= range01(as.numeric(ChlRFU))),color="blue") 
 p <- p + scale_y_continuous(name = "First Axis", sec.axis = sec_axis(trans = ~.*.05, name="Second Axis")
  ) 
  # geom_line(aes(y = range01(as.numeric(Corr.NTU))), color="green") +
  # geom_line(aes(y= range01(as.numeric(ChlRFU))),color="blue") +
  # geom_line(aes(y = range01(as.numeric(saltppt))),color="red") +
  # geom_line(aes(y = range01(as.numeric(TempC))),color="purple") +
  # geom_line(aes(y = range01(as.numeric(Doper))),color="orange")+
   p <- p + ggtitle("Storms")+labs(x="Time")
 print(p)
}

range01 <- function(x, na.rm = TRUE) {
  # version 1.1 (9 Aug 2013)
  (x - min(x, na.rm = na.rm)) / (max(x, na.rm = na.rm) - min(x, na.rm = na.rm))
}

using base R

for(i in 1:length(start)){
index <- c((start[i]-24):(end[i]+24))

date <- c(hilomodified$date[index])
enddate <- hilomodified$date[end[i]+24]
endcms <- as.numeric(hilomodified$cms[end[i]+24])
endchl <- range01(as.numeric(hilomodified$cms[end[i]+24]))
endturb <- as.numeric(hilomodified$cms[end[i]+24])
endsalt <- as.numeric(hilomodified$cms[end[i]+24])
endtemp <- as.numeric(hilomodified$cms[end[i]+24])
endDO <- as.numeric(hilomodified$cms[end[i]+24])

par(mar = c(5, 4, 4, 4) + 0.3) # Additional space for second y-axis
plot(x = date,y = as.numeric(hilomodified$cms[index]), type = "l",lwd=2, col="black", xlab="Time") # Create first plot for River Flow

par(new = TRUE) # Add new plot
plot(x = date ,y = range01(as.numeric(hilomodified$ChlRFU[index])),axes = FALSE, type = "l",lwd=2, col="blue", ylab = "Time")  # Create second plot without axes
lines(x = date ,y = range01(as.numeric(hilomodified$Corr.NTU[index])), type = "l",lwd=2, col="red")
lines(x = date ,y = range01(as.numeric(hilomodified$saltppt[index])), type = "l",lwd=2, col="green")
lines(x = date ,y = range01(as.numeric(hilomodified$TempC[index])), type = "l",lwd=2, col="orange")
lines(x = date ,y = range01(as.numeric(hilomodified$Doper[index])), type = "l",lwd=2, col="purple")
axis(side = 4)   # Add second axis
#mtext("y2", side = 4, line = 3) # Add second axis label

text(x= enddate, y = endcms, col = "black", adj=1, cex=0.85, label= "River Flow")
text(x= enddate, y = endchl, col = "blue", adj=1, cex=0.85, label= "CHL")
text(x= enddate, y = endturb, col = "red", adj=1, cex=0.85, label= "TURB")
text(x= enddate, y = endsalt, col = "green", adj=1, cex=0.85, label= "Salinity")
text(x= enddate, y = endtemp, col = "orange", adj=1, cex=0.85, label= "TEMP")
text(x= enddate, y = endDO, col = "purple", adj=1, cex=0.85, label= "DIS")
}

LS0tCnRpdGxlOiAiRGF0YSBDbGVhbmluZyAmIERlc2NyaXB0aXZlcyIKYXV0aG9yOiAiQnJpYW5uYSBDaXJpbGxvICYgT2RhbHlzIEJhcnJpZW50b3MiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyBNYXRjaGluZyB0aGUgYm91eSBkYXRhIHRvIHRoZSBvdGhlciBkYXRhIGNvbGxlY3RlZCAKYGBge3J9CmhpbG8gPC0gaGJiX3drdV9oX3h0cwpoaWxvIDwtIGRhdGEuZnJhbWUoZGF0ZT1pbmRleChoaWxvKSwgY29yZWRhdGEoaGlsbykpCmhpbG8gPC0gaGlsb1s1Mjk6NTQ4MTYsXQpoaWxvCiMgd2hpY2goaGlsbyRkYXRlPT0iMjAxMC0xMC0yMyAwMDowMDowMCIpID0gaW5kZXggNTI5IAoKIyB3aGljaChoaWxvJGRhdGU9PSIyMDE2LTEyLTMxIDIzOjAwOjAwIikgPSBpbmRleCA1NDgxNgpgYGAKYGBge3J9Cmxlbmd0aChoaWxvWywxXSkgIyB3ZSBhcmUgbGVmdCB3aXRoIDU0Mjg4IGxpbmVzIG9mIGRhdGEKCjU0ODE2IC0gbGVuZ3RoKGhpbG9bLDFdKSAjIHdlIGxvc3QgNTI4IHZhbHVlcyAKYGBgCgojIENoYW5naW5nIGNvbHVtbiBuYW1lcyAKYGBge3J9CiMgcmVtb3ZpbmcgY29sdW1ucyB0aGF0IHdlIGFyZSBub3QgdXNpbmcgCmhpbG8kZGF0ZS4yIDwtIE5VTEwgIyBhbm90aGVyIGRhdGUgY29sdW1uCmhpbG8kZGF0ZS4xIDwtIE5VTEwgIyBhbm90aGVyIGRhdGUgY29sdW1uCmhpbG8kQkdBUkZVIDwtIE5VTEwgIyA/CmhpbG8kY2ZzIDwtIE5VTEwKaGlsbyRET21nTCA8LSBOVUxMICMgZGlzc29sdmVkIG94eWdlbgojaGlsbyREb3BlciA8LSBOVUxMICMgZGlzc29sdmVkIG94eWdlbgpoaWxvJFBBUjEgPC0gTlVMTCAjID8KaGlsbyRwSCA8LSBOVUxMICMgcEgKaGlsbyROVFUgPC0gTlVMTCAjIGEgZGlmZmVyZW50IG1lYXN1cmVtZW50IGZvciB0dXJiaXRpdHkKaGlsbyRET3BlcjEwIDwtIE5VTEwgIyBkaXNzb2x2ZWQgb3h5Z2VuCgojIGNvbG5hbWVzKGhpbG8pIDwtIGMoIkRhdGUiLCAiY2ZzIiwgIlJpdmVyRmxvdy1jdW1lYyIsICJMb2dSaXZlckZsb3ctY3VtZWMiLCAiQ2hsb3JvcGh5bGwtUkZVIiwgIlNhbGluaXR5LVBQVCIsICJUZW1wLUMiLCAiY2hsb3JvcGh5bGwtY2FsaWJyYXRvciIsICJUdXJiaWRpdHktTlRVIikKIyBkb2VzIG5vdCB3b3JrID8/PwoKaGlsbwpgYGAKCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgRlVMTCBEQVRBIFNFVCAyMDEyLTIwMTYKIyBEZXNjcmlwdGl2ZXM6IFBMb3RzCgojIyBSaXZlciBGbG93IEZVTEwgREFUQSBTRVQKYGBge3J9Cmxlbmd0aChoaWxvJGxvZ2Ntc1t3aGljaChpcy5uYShoaWxvJGxvZ2Ntcyk9PVRSVUUpXSkgIyAxMiBOQXMgCndoaWNoKGlzLm5hKGhpbG8kbG9nY21zKT09VFJVRSkKClJpdmVyRmxvdyA8LSBnZ3Bsb3QoaGlsbywgIGFlcyh4ID0gZGF0ZSwgeSA9IGFzLm51bWVyaWMoY21zKSkpICsgCiAgZ2VvbV9saW5lKCkKCnByaW50KFJpdmVyRmxvdyArIGdndGl0bGUoIlJpdmVyIEZsb3ciKStsYWJzKHg9IlRpbWUiLCB5ID0gIlJpdmVyIEZsb3cgLSBjdWJpYyBtZXRlcnMgcGVyIHNlY29uZCIpKQpgYGAKIyMgQ0hMIEZVTEwgREFUQSBTRVQKYGBge3J9Cmxlbmd0aChoaWxvJENobFJGVVt3aGljaChpcy5uYShoaWxvJENobFJGVSk9PVRSVUUpXSkgIyAyMDQ2NCBOQXMKCndoaWNoKGFzLm51bWVyaWMoaGlsbyRDaGxSRlUpPT1tYXgoYXMubnVtZXJpYyhuYS5vbWl0KGhpbG8kQ2hsUkZVKSkpKSAjIDE1LjMgbWF4IAojIENITCB0ZWxscyB1cyB3aGVyZSBpbiB0aGUgZGF0YSBzZXQgdGhpcyBoYXBwZW5lZCAgCmhpbG9bMzg5NzQsXQoKQ0hMIDwtIGdncGxvdChoaWxvLCAgYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhDaGxSRlUpKSkgKyAKICBnZW9tX2xpbmUoKQoKcHJpbnQoQ0hMICsgZ2d0aXRsZSgiQ2hsb3JvcGh5bGwgIikrbGFicyh4PSJUaW1lIiwgeSA9ICJDaGxvcm9waHlsbCAgLSByZWxhdGl2ZSBmbHVvcmVzY2VuY2UgdW5pdHMgKFJGVSkiKSkKYGBgCiMjIFR1cmJpdHkgRlVMTCBEQVRBIFNFVApgYGB7cn0KbGVuZ3RoKGhpbG8kQ29yci5OVFVbd2hpY2goaXMubmEoaGlsbyRDb3JyLk5UVSk9PVRSVUUpXSkgIzE1MDEyIE5BcwoKd2hpY2goYXMubnVtZXJpYyhoaWxvJENvcnIuTlRVKT09bWF4KGFzLm51bWVyaWMobmEub21pdChoaWxvJENvcnIuTlRVKSkpKSAjIDg4LjQKIyB0ZWxscyB1cyB3aGVyZSBpbiB0aGUgZGF0YSBzZXQgdGhpcyBoYXBwZW5lZApoaWxvWzMzMjQzLF0KClRVUkIgPC0gZ2dwbG90KGhpbG8sYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhDb3JyLk5UVSkpKSArIAogIGdlb21fbGluZSgpCgpwcmludChUVVJCICsgZ2d0aXRsZSgiVHVyYmlkaXR5ICIpK2xhYnMoeD0iVGltZSIsIHkgPSAiVHVyYmlkaXR5IC0gTmVwaGVsb21ldHJpYyBUdXJiaWRpdHkgVW5pdHMgKE5UVSkiKSkKYGBgCiMjIFNhbGluaXR5IEZVTEwgREFUQSBTRVQKYGBge3J9Cmxlbmd0aChoaWxvJHNhbHRwcHRbd2hpY2goaXMubmEoaGlsbyRzYWx0cHB0KT09VFJVRSldKSAjMTEzMzAgTkFzCgpTQUxUIDwtIGdncGxvdChoaWxvLCAgYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhzYWx0cHB0KSkpICsgCiAgZ2VvbV9saW5lKCkKCnByaW50KFNBTFQgKyBnZ3RpdGxlKCJTYWxpbml0eSIpK2xhYnMoeD0iVGltZSIsIHkgPSAiU2FsaW5pdHkgLSB1bml0IHBhcnRzIHBlciB0aG91c2FuZCAoUFBUKSIpKQpgYGAKCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgSGlzdG9ncmFtcyBGVUxMIERBVEEgU0VUCiMjIFJpdmVyIEZsb3cgSGlzdG9ncmFtCmBgYHtyfQpoaXN0KGFzLm51bWVyaWMoaGlsbyRsb2djbXMpLCBtYWluID0gIkhpc3RvZ3JhbSBvZiBMb2cgUml2ZXIgRmxvdyIsIHhsYWIgPSAiTG9nIFJpdmVyIEZsb3ciKQoKIyB0aGlzIGxvb2tzIG9rYXkKYGBgCiMjIENITCBIaXN0b2dyYW0KYGBge3J9CiMgVkVSWSBza2V3ZWQKaGlzdChhcy5udW1lcmljKGhpbG8kQ2hsUkZVKSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgQ2hsb3JvcGh5bGwiLCB4bGFiID0gIkNobG9yb3BoeWxsICAtIHJlbGF0aXZlIGZsdW9yZXNjZW5jZSB1bml0cyAoUkZVKSIpCgojIHRoaXMgbG9va3MgYmV0dGVyCmhpc3QobG9nKGFzLm51bWVyaWMoaGlsbyRDaGxSRlUpKSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTG9nIENobG9yb3BoeWxsIiwgeGxhYiA9ICJDaGxvcm9waHlsbCIpCiMgbm90IHN1cmUgd2hhdCBoYXBwZW5zIHRvIHVuaXRzIHdoZW4gdGFraW5nIHRoZSBsb2cgCmBgYAojIyBUdXJiaXR5IEhpc3RvZ3JhbQpgYGB7cn0KIyBWRVJZIHNrZXdlZApoaXN0KGFzLm51bWVyaWMoaGlsbyRDb3JyLk5UVSksIG1haW4gPSAiSGlzdG9ncmFtIG9mIFR1cmJpZGl0eSIsIHhsYWIgPSAiVHVyYmlkaXR5IC0gTmVwaGVsb21ldHJpYyBUdXJiaWRpdHkgVW5pdHMgKE5UVSkiKQoKIyB0aGlzIGxvb2tzIGJldHRlcgpoaXN0KGxvZyhhcy5udW1lcmljKGhpbG8kQ29yci5OVFUpKSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTG9nIFR1cmJpZGl0eSIsIHhsYWIgPSAiVHVyYmlkaXR5IikKIyBub3Qgc3VyZSB3aGF0IGhhcHBlbnMgdG8gdW5pdHMgd2hlbiB0YWtpbmcgdGhlIGxvZyAKYGBgCiMjIFNhbGluaXR5IEhpc3RvZ3JhbQpgYGB7cn0KIyBza2V3ZWQKaGlzdChhcy5udW1lcmljKGhpbG8kc2FsdHBwdCksIG1haW4gPSAiSGlzdG9ncmFtIG9mIFNhbGluaXR5IiwgeGxhYiA9ICJTYWxpbml0eSAtIHVuaXQgcGFydHMgcGVyIHRob3VzYW5kIChQUFQpIikKCiMgdGhpcyBpcyB3b3JzdCEKaGlzdChsb2coYXMubnVtZXJpYyhoaWxvJHNhbHRwcHQpKSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTG9nIFNhbGluaXR5IiwgeGxhYiA9ICJTYWxpbml0eSIpCiMgbm90IHN1cmUgd2hhdCBoYXBwZW5zIHRvIHVuaXRzIHdoZW4gdGFraW5nIHRoZSBsb2cgCmBgYAoKPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgTkVXIERBVEEgU0VULU1vZGlmaWVkIERhdGEgMjAxMy0yMDE1CmBgYHtyfQojIHN0YXJ0IGRhdGU6IDIwMTMtMDEtMDEgMDA6MDA6MDAKIyBlbmQgZGF0ZTogMjAxNS0xMi0zMSAyMzowMDowMApoaWxvbW9kaWZpZWQgPC0gaGlsb1sxOTIyNTo0NTUwNCxdCmxlbmd0aChoaWxvWywxXSktbGVuZ3RoKGhpbG9tb2RpZmllZFssMV0pCiMgbG9zdCAyODAwOCBlbnRyaWVzIG9mIGRhdGEgCgpsZW5ndGgoaGlsb21vZGlmaWVkWywxXSktNTI4ICMgd2UgYXJlIGxlZnQgd2l0aCAyNTc1MiBlbnRyaWVzIG9mIGRhdGEgCgoKaGVhZChoaWxvbW9kaWZpZWQpCnRhaWwoaGlsb21vZGlmaWVkKQoKYGBgCgojIERlc2NyaXB0aXZlcyBvbiBhbGwgdmFyaWFibGVzIE1PRElGSUVEIERBVEEgU0VUOiBVc2luZyBGYXZzdGF0cwojIyBSaXZlciBGbG93IEZhdnN0YXRzCmBgYHtyfQpsaWJyYXJ5KG1vc2FpYykKZmF2c3RhdHMoaGlsb21vZGlmaWVkJGNtcykKYGBgCiMjIENITCBGYXZzdGF0cwpgYGB7cn0KZmF2c3RhdHMoaGlsb21vZGlmaWVkJENobFJGVSkKYGBgCiMjIFR1cmJpdGl0eSBGYXZzdGF0cwpgYGB7cn0KZmF2c3RhdHMoaGlsb21vZGlmaWVkJENvcnIuTlRVKQpgYGAKIyMgU2FsaW5pdHkgRmF2c3RhdHMKYGBge3J9CmZhdnN0YXRzKGhpbG9tb2RpZmllZCRzYWx0cHB0KQpmYXZzdGF0cyhoaWxvbW9kaWZpZWQkVGVtcEMpCmZhdnN0YXRzKGhpbG9tb2RpZmllZCREb3BlcikKYGBgCgo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIE1PRElGSUVEIERBVEEgU0VUIDIwMTMtMjAxNQojIERlc2NyaXB0aXZlczogUGxvdHMKCiMjIFJpdmVyIEZsb3cgTU9ESUZJRUQKYGBge3J9Cmxlbmd0aChoaWxvbW9kaWZpZWQkbG9nY21zW3doaWNoKGlzLm5hKGhpbG9tb2RpZmllZCRsb2djbXMpPT1UUlVFKV0pICMgTm8gTkFzLCBZQVkhCndoaWNoKGlzLm5hKGhpbG9tb2RpZmllZCRsb2djbXMpPT1UUlVFKQoKUml2ZXJGbG93TW9kIDwtIGdncGxvdChoaWxvbW9kaWZpZWQsICBhZXMoeCA9IGRhdGUsIHkgPSBhcy5udW1lcmljKGNtcykpKSArIAogIGdlb21fbGluZSgpCgpwcmludChSaXZlckZsb3dNb2QgKyBnZ3RpdGxlKCJSaXZlciBGbG93IikrbGFicyh4PSJUaW1lIiwgeSA9ICJSaXZlciBGbG93IC0gY3ViaWMgbWV0ZXJzIHBlciBzZWNvbmQiKSkKYGBgCiMjIENITCBNT0RJRklFRApgYGB7cn0Kc3VtKGlzLm5hKGhpbG9tb2RpZmllZCRDaGxSRlUpPT1UUlVFKSAjIDE4ODQgTkFzCiN3aGljaChpcy5uYShoaWxvbW9kaWZpZWQkQ2hsUkZVKT09VFJVRSkKIyBtYXgoYXMubnVtZXJpYyhuYS5vbWl0KGhpbG8kQ2hsUkZVKSkpICMgMTUuMwp3aGljaChhcy5udW1lcmljKGhpbG9tb2RpZmllZCRDaGxSRlUpPT0xNS4zKQpoaWxvWzM4OTc0LF0KCkNITE1vZCA8LSBnZ3Bsb3QoaGlsb21vZGlmaWVkLCAgYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhDaGxSRlUpKSkgKyAKICBnZW9tX2xpbmUoKQoKcHJpbnQoQ0hMTW9kICsgZ2d0aXRsZSgiQ2hsb3JvcGh5bGwgIikrbGFicyh4PSJUaW1lIiwgeSA9ICJDaGxvcm9waHlsbCAgLSByZWxhdGl2ZSBmbHVvcmVzY2VuY2UgdW5pdHMgKFJGVSkiKSkKYGBgCgoKIyBUdXJiaXRpdHkgTU9ESUZJRUQKYGBge3J9Cmxlbmd0aChoaWxvbW9kaWZpZWQkQ29yci5OVFVbd2hpY2goaXMubmEoaGlsb21vZGlmaWVkJENvcnIuTlRVKT09VFJVRSldKSAjIDI3MDQgTkFzCiMgbWF4KGFzLm51bWVyaWMobmEub21pdChoaWxvJENvcnIuTlRVKSkpICMgODguNAp3aGljaChhcy5udW1lcmljKGhpbG8kQ29yci5OVFUpPT04OC40KQpoaWxvWzMzMjQzLF0KClRVUkJNb2QgPC0gZ2dwbG90KGhpbG9tb2RpZmllZCwgIGFlcyh4ID0gZGF0ZSwgeSA9IGFzLm51bWVyaWMoQ29yci5OVFUpKSkgKyAKICBnZW9tX2xpbmUoKQoKcHJpbnQoVFVSQk1vZCArIGdndGl0bGUoIlR1cmJpZGl0eSAiKStsYWJzKHg9IlRpbWUiLCB5ID0gIlR1cmJpZGl0eSAtIE5lcGhlbG9tZXRyaWMgVHVyYmlkaXR5IFVuaXRzIChOVFUpIikpCmBgYAoKIyBTYWxpbml0eSBNT0RJRklFRApgYGB7cn0KbGVuZ3RoKGhpbG9tb2RpZmllZCRzYWx0cHB0W3doaWNoKGlzLm5hKGhpbG9tb2RpZmllZCRzYWx0cHB0KT09VFJVRSldKSAjIDIyNjcgTkFzCgpTQUxUTW9kIDwtIGdncGxvdChoaWxvbW9kaWZpZWQsICBhZXMoeCA9IGRhdGUsIHkgPSBhcy5udW1lcmljKHNhbHRwcHQpKSkgKyAKICBnZW9tX2xpbmUoKQoKcHJpbnQoU0FMVE1vZCArIGdndGl0bGUoIlNhbGluaXR5IikrbGFicyh4PSJUaW1lIiwgeSA9ICJTYWxpbml0eSAtIHVuaXQgcGFydHMgcGVyIHRob3VzYW5kIChQUFQpIikpCmBgYAojIFRlbXB1cmF0dXJlIE1PRElGSUVECmBgYHtyfQpsZW5ndGgoaGlsb21vZGlmaWVkJFRlbXBDW3doaWNoKGlzLm5hKGhpbG9tb2RpZmllZCRUZW1wQyk9PVRSVUUpXSkgIyAyMjY3IE5BcwoKVGVtcE1vZCA8LSBnZ3Bsb3QoaGlsb21vZGlmaWVkLCAgYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhUZW1wQykpKSArIAogIGdlb21fbGluZSgpCgpwcmludChUZW1wTW9kICsgZ2d0aXRsZSgiVGVtcGVyYXR1cmUiKStsYWJzKHg9IlRpbWUiLCB5ID0gIlRlbXBlcmF0dXJlIC0gQ2Vsc2l1cyIpKQpgYGAKIyBEaXNzb2x2ZWQgT3h5Z2VuIE1PRElGSUVECmBgYHtyfQpsZW5ndGgoaGlsb21vZGlmaWVkJERvcGVyW3doaWNoKGlzLm5hKGhpbG9tb2RpZmllZCREb3Blcik9PVRSVUUpXSkgIyAyMjY3IE5BcwoKVGVtcE1vZCA8LSBnZ3Bsb3QoaGlsb21vZGlmaWVkLCAgYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhEb3BlcikpKSArIAogIGdlb21fbGluZSgpCgpwcmludChUZW1wTW9kICsgZ2d0aXRsZSgiRGlzc29sdmVkIE94eWdlbiIpK2xhYnMoeD0iVGltZSIsIHkgPSAiRGlzc29sdmVkIE94eWdlbiBpbiBwZXJjZW50IG9mIHNhdHVyYXRpb24iKSkKYGBgCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIEhpc3RvZ3JhbXMgTU9ESUZJRUQgCgojIyBSaXZlciBGbG93IE1PRElGSUVECmBgYHtyfQpoaXN0KGFzLm51bWVyaWMoaGlsb21vZGlmaWVkJGNtcyksIG1haW4gPSAiSGlzdG9ncmFtIG9mIExvZyBSaXZlciBGbG93IiwgeGxhYiA9ICJMb2cgUml2ZXIgRmxvdyIsIGJyZWFrcyA9OTAsIHhsaW0gPSBjKDAsMTAwKSkKCiMgdGhpcyBsb29rcyBva2F5CmBgYAojIyBDSEwgTU9ESUZJRUQKYGBge3J9CiMgVkVSWSBza2V3ZWQKaGlzdChhcy5udW1lcmljKGhpbG9tb2RpZmllZCRDaGxSRlUpLCBtYWluID0gIkhpc3RvZ3JhbSBvZiBDaGxvcm9waHlsbCIsIHhsYWIgPSAiQ2hsb3JvcGh5bGwgIC0gcmVsYXRpdmUgZmx1b3Jlc2NlbmNlIHVuaXRzIChSRlUpIikKCiMgdGhpcyBsb29rcyBiZXR0ZXIKaGlzdChsb2coYXMubnVtZXJpYyhoaWxvbW9kaWZpZWQkQ2hsUkZVKSksIG1haW4gPSAiSGlzdG9ncmFtIG9mIExvZyBDaGxvcm9waHlsbCIsIHhsYWIgPSAiQ2hsb3JvcGh5bGwiKQojIG5vdCBzdXJlIHdoYXQgaGFwcGVucyB0byB1bml0cyB3aGVuIHRha2luZyB0aGUgbG9nIApgYGAKIyMgVHVyYml0aXR5IE1PRElGSUVECmBgYHtyfQojIFZFUlkgc2tld2VkCmhpc3QoYXMubnVtZXJpYyhoaWxvbW9kaWZpZWQkQ29yci5OVFUpLCBtYWluID0gIkhpc3RvZ3JhbSBvZiBUdXJiaWRpdHkiLCB4bGFiID0gIlR1cmJpZGl0eSAtIE5lcGhlbG9tZXRyaWMgVHVyYmlkaXR5IFVuaXRzIChOVFUpIikKCiMgdGhpcyBsb29rcyBiZXR0ZXIKaGlzdChsb2coYXMubnVtZXJpYyhoaWxvbW9kaWZpZWQkQ29yci5OVFUpKSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTG9nIFR1cmJpZGl0eSIsIHhsYWIgPSAiVHVyYmlkaXR5IikKIyBub3Qgc3VyZSB3aGF0IGhhcHBlbnMgdG8gdW5pdHMgd2hlbiB0YWtpbmcgdGhlIGxvZyAKYGBgCiMjIFNhbGluaXR5IE1PRElGSUVECmBgYHtyfQojIHNrZXdlZApoaXN0KGFzLm51bWVyaWMoaGlsb21vZGlmaWVkJHNhbHRwcHQpLCBtYWluID0gIkhpc3RvZ3JhbSBvZiBTYWxpbml0eSIsIHhsYWIgPSAiU2FsaW5pdHkgLSB1bml0IHBhcnRzIHBlciB0aG91c2FuZCAoUFBUKSIpCgojIHRoaXMgaXMgd29yc3QhCmhpc3QobG9nKGFzLm51bWVyaWMoaGlsb21vZGlmaWVkJHNhbHRwcHQpKSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTG9nIFNhbGluaXR5IiwgeGxhYiA9ICJTYWxpbml0eSIpCiMgbm90IHN1cmUgd2hhdCBoYXBwZW5zIHRvIHVuaXRzIHdoZW4gdGFraW5nIHRoZSBsb2cgCmBgYAo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIFBsb3Qgd2l0aCBBTEwgVmFyIDIwMTMtMjAxNQpJdCBpcyBoYXJkIHRvIHNlZSB3aGF0IGlzIGdvaW5nIG9uIApgYGB7cn0KQWxsWWVhcnMgPC0gZ2dwbG90KGhpbG9tb2RpZmllZCwgIGFlcyh4ID0gZGF0ZSwgeSA9IGFzLm51bWVyaWMobG9nY21zKSkpICsgCiAgZ2VvbV9saW5lKCkrCiAgZ2VvbV9saW5lKGFlcyh5ID0gYXMubnVtZXJpYyhzYWx0cHB0KSksIGNvbG9yID0gImRhcmtyZWQiKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gYXMubnVtZXJpYyhDb3JyLk5UVSkpLCBjb2xvcj0iZGFya2dyZWVuIikgKwogIGdlb21fbGluZShhZXMoeT1hcy5udW1lcmljKENobFJGVSkpLGNvbG9yPSJibHVlIikKCnByaW50KEFsbFllYXJzICsgZ2d0aXRsZSgiSGlsbyBCYXkiKStsYWJzKHg9IlRpbWUiLCB5ID0gIlJpdmVyIEZsb3cgLSBjdWJpYyBtZXRlcnMgcGVyIHNlY29uZCIpKQoKYGBgCgoKPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBEZXNjcmlwdGl2ZXMgYnkgU3Rvcm0KV2UgYXJlIHBpY2tpbmcgb25lIHN0b3JtIGZyb20gZWFjaCB5ZWFyLiBXZSBjYW4gaW5kaWNhdGUgYSBzdG9ybSBoYXMgb2NjdXJyZWQgYnkgdGhlIGV4dHJlbWUgZXZlbnRzIGluIHRoZSByaXZlciBmbG93IGRhdGEuIApXZSB3aWxsIG5vdCB1c2UgdGhlIGxvZyAod2hpY2ggaXMgbG9nYmFzZTEwKSBpbiBvcmRlciB0byBzZWUgdGhlIGV4dHJlbWUgZXZlbnRzCldoZW4gc2FsaW5pdHkgaXMgYmVsb3cgMzUgdGhpcyBhbHNvIGluZGljYXRlcyBhIHN0b3JtIGhhcyBvY2N1cnJlZC4gCgpXZSB3aWxsIGJyZWFrIHRoZSBkYXRhIHNldCBieSB5ZWFyIHRvIGZpbmQgdGhlIG1vc3QgZXh0cmVtZSBldmVudCBmb3IgZWFjaCB5ZWFyLiAKYGBge3J9CmhpbG8yMDEzIDwtIGhpbG9tb2RpZmllZFsxOjg3NjAsXQoKaGlsbzIwMTQgPC0gaGlsb21vZGlmaWVkWzg3NjE6MTc1MjAsXQoKaGlsbzIwMTUgPC0gaGlsb21vZGlmaWVkWzE3NTIxOmxlbmd0aChoaWxvbW9kaWZpZWRbLDFdKSxdCmBgYAoKIyAyMDEzIERhdGEgJiBQbG90CmBgYHtyfQojIG1heChhcy5udW1lcmljKGhpbG8yMDEzJGxvZ2NtcykpICMgdGhpcyBpcyBsb2cgYmFzZSAxMCAKIyBUaGlzIGlzIE5PVCB0aGUgbmF0dXJhbCBsb2cKbWF4KGFzLm51bWVyaWMoaGlsbzIwMTMkY21zKSkgIyAyMDcuMTg2IAp3aGljaChhcy5udW1lcmljKGhpbG8yMDEzJGNtcykgPT0gbWF4KGFzLm51bWVyaWMoaGlsbzIwMTMkY21zKSkpCgpoaWxvMjAxM1szNTUwLF0KIyBhbGwgdmFsdWVzIGZvciB0aGlzIHN0b3JtIGFyZSBOQQoKcGxvdDIwMTMgPC0gZ2dwbG90KGhpbG8yMDEzLCAgYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhjbXMpKSkgKyAKICBnZW9tX2xpbmUoY29sb3I9ImJsYWNrIikrCiAgZ2VvbV9saW5lKGFlcyh5ID0gYXMubnVtZXJpYyhzYWx0cHB0KSksIGNvbG9yID0gImRhcmtyZWQiKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gYXMubnVtZXJpYyhDb3JyLk5UVSkpLCBjb2xvcj0iZGFya2dyZWVuIikgKwogIGdlb21fbGluZShhZXMoeT1hcy5udW1lcmljKENobFJGVSkpLGNvbG9yPSJibHVlIikKCnByaW50KHBsb3QyMDEzICsgZ2d0aXRsZSgiMjAxMyIpK2xhYnMoeD0iVGltZSIsIHkgPSAiUml2ZXIgRmxvdyAtIGN1YmljIG1ldGVycyBwZXIgc2Vjb25kIikpCmBgYAoKIyMjIyBTcGxpdCAyMDEzIGludG8gNiBtb250aHMgdG8gZ2V0IGEgYmV0dGVyIHZpc3VhbApgYGB7cn0KIyBSMjAxMy4xIDwtIGdncGxvdChoaWxvMjAxM1sxOihsZW5ndGgoaGlsbzIwMTNbLDFdKS8yKSxdLCAgYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhjbXMpKSkgKyAKIyAgIGdlb21fbGluZShjb2xvcj0iYmxhY2siKSsKIyAgIGdlb21fbGluZShhZXMoeSA9IGFzLm51bWVyaWMoc2FsdHBwdCkpLCBjb2xvciA9ICJkYXJrcmVkIikgKwojICAgZ2VvbV9saW5lKGFlcyh5ID0gYXMubnVtZXJpYyhDb3JyLk5UVSkpLCBjb2xvcj0iZGFya2dyZWVuIikgKwojICAgZ2VvbV9saW5lKGFlcyh5PWFzLm51bWVyaWMoQ2hsUkZVKSksY29sb3I9ImJsdWUiKQojIHByaW50KFIyMDEzLjEgKyBnZ3RpdGxlKCJSaXZlciBGbG93IikrbGFicyh4PSJUaW1lIiwgeSA9ICJSaXZlciBGbG93IC0gY3ViaWMgbWV0ZXJzIHBlciBzZWNvbmQiKSkKIyBSMjAxMy4xK3lsaW0oMCw0MCkKIyAKIyAKIyBSMjAxMy4yIDwtIGdncGxvdChoaWxvMjAxM1sobGVuZ3RoKGhpbG8yMDEzWywxXSkvMik6bGVuZ3RoKGhpbG8yMDEzWywxXSksXSwgIGFlcyh4ID0gZGF0ZSwgeSA9IGFzLm51bWVyaWMoY21zKSkpICsgCiMgICBnZW9tX2xpbmUoY29sb3I9ImJsYWNrIikrCiMgICBnZW9tX2xpbmUoYWVzKHkgPSBhcy5udW1lcmljKHNhbHRwcHQpKSwgY29sb3IgPSAiZGFya3JlZCIpICsKIyAgIGdlb21fbGluZShhZXMoeSA9IGFzLm51bWVyaWMoQ29yci5OVFUpKSwgY29sb3I9ImRhcmtncmVlbiIpICsKIyAgIGdlb21fbGluZShhZXMoeT1hcy5udW1lcmljKENobFJGVSkpLGNvbG9yPSJibHVlIikKIyBwcmludChSMjAxMy4yICsgZ2d0aXRsZSgiUml2ZXIgRmxvdyIpK2xhYnMoeD0iVGltZSIsIHkgPSAiUml2ZXIgRmxvdyAtIGN1YmljIG1ldGVycyBwZXIgc2Vjb25kIikpCiMgUjIwMTMuMit5bGltKDAsNDApCmBgYAoKIyAyMDE0IERhdGEgJiBQbG90CmBgYHtyfQojIE1heCByaXZlciBmbG93IGluIHRoZSBvdmVyYWxsIGRhdGEgc2V0Cm1heChhcy5udW1lcmljKGhpbG8yMDE0JGNtcykpCm1heChhcy5udW1lcmljKGhpbG9tb2RpZmllZCRjbXMpKQoKd2hpY2goYXMubnVtZXJpYyhoaWxvMjAxNCRjbXMpID09IG1heChhcy5udW1lcmljKGhpbG8yMDE0JGNtcykpKQoKaGlsbzIwMTRbNTI2MyxdCgpSMjAxNCA8LSBnZ3Bsb3QoaGlsbzIwMTQsICBhZXMoeCA9IGRhdGUsIHkgPSBhcy5udW1lcmljKGxvZ2NtcykpKSArIAogIGdlb21fbGluZShjb2xvcj0iYmxhY2siKSsKICBnZW9tX2xpbmUoYWVzKHkgPSBhcy5udW1lcmljKHNhbHRwcHQpKSwgY29sb3IgPSAiZGFya3JlZCIpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBhcy5udW1lcmljKENvcnIuTlRVKSksIGNvbG9yPSJkYXJrZ3JlZW4iKSArCiAgZ2VvbV9saW5lKGFlcyh5PWFzLm51bWVyaWMoQ2hsUkZVKSksY29sb3I9ImJsdWUiKQoKcHJpbnQoUjIwMTQgKyBnZ3RpdGxlKCIyMDE0IikrbGFicyh4PSJUaW1lIiwgeSA9ICJSaXZlciBGbG93IC0gY3ViaWMgbWV0ZXJzIHBlciBzZWNvbmQiKSkKYGBgCgoKIyAyMDE1IERhdGEgJiBQbG90CmBgYHtyfQptYXgoYXMubnVtZXJpYyhoaWxvMjAxNSRjbXMpKQoKd2hpY2goYXMubnVtZXJpYyhoaWxvMjAxNSRjbXMpID09IG1heChhcy5udW1lcmljKGhpbG8yMDE1JGNtcykpKQoKaGlsbzIwMTVbNjQ3NSxdCgpSMjAxNSA8LSBnZ3Bsb3QoaGlsbzIwMTUsICBhZXMoeCA9IGRhdGUsIHkgPSBhcy5udW1lcmljKGxvZ2NtcykpKSArIAogIGdlb21fbGluZShjb2xvcj0iYmxhY2siKSsKICBnZW9tX2xpbmUoYWVzKHkgPSBhcy5udW1lcmljKHNhbHRwcHQpKSwgY29sb3IgPSAiZGFya3JlZCIpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBhcy5udW1lcmljKENvcnIuTlRVKSksIGNvbG9yPSJkYXJrZ3JlZW4iKSArCiAgZ2VvbV9saW5lKGFlcyh5PWFzLm51bWVyaWMoQ2hsUkZVKSksY29sb3I9ImJsdWUiKQoKcHJpbnQoUjIwMTUgKyBnZ3RpdGxlKCIyMDE1IikrbGFicyh4PSJUaW1lIiwgeSA9ICJSaXZlciBGbG93IC0gY3ViaWMgbWV0ZXJzIHBlciBzZWNvbmQiKSkKYGBgCgoKIyBTZXBhcmF0aW5nIHRoZSBEYXRhIGJ5IFN0b3JtIEV2ZW50cwo9PT09PT09CiMgU2VwYXJhdGluZyB0aGUgRGF0YSBieSBTdG9ybQoKYGBge3J9Cm91dGNvbWVzIDwtIGFzLm51bWVyaWMoaGlsb21vZGlmaWVkJHNhbHRwcHQpPDI1IAppbmRleC5sdDI1IDwtIHdoaWNoKG91dGNvbWVzPT1UUlVFKQoKcG9zcy5zdG9ybXMgPC0gaGlsb21vZGlmaWVkW2luZGV4Lmx0MjUsXQpwb3NzLnN0b3JtcwpgYGAKCgpgYGB7cn0Kb3V0Y29tZXMuMzUgPC0gYXMubnVtZXJpYyhoaWxvbW9kaWZpZWQkc2FsdHBwdCk8MzUgCmluZGV4Lmx0MzUgPC0gd2hpY2gob3V0Y29tZXM9PVRSVUUpCmluZGV4Lmx0MjUKcG9zcy5zdG9ybXMzNSA8LSBoaWxvbW9kaWZpZWRbaW5kZXgubHQyNSxdCnBvc3Muc3Rvcm1zMzUKCmhpbG9tb2RpZmllZCRkYXRlWzE2XQpgYGAKCmBgYHtyfQpzdG9ybS4xLjcuMTMgPC0gZ2dwbG90KGhpbG9tb2RpZmllZFsxNDU6MTY4LF0sICBhZXMoeCA9IGRhdGUsIHkgPSBhcy5udW1lcmljKGNtcykpKSArIAogIGdlb21fbGluZShjb2xvcj0iYmxhY2siKSsKICBnZW9tX2xpbmUoYWVzKHkgPSBhcy5udW1lcmljKHNhbHRwcHQpKSwgY29sb3IgPSAibGlnaHRzdGVlbGJsdWUxIikgKwogIGdlb21fbGluZShhZXMoeSA9IGFzLm51bWVyaWMoQ29yci5OVFUpKSwgY29sb3I9ImdyZXk2OSIpICsKICBnZW9tX2xpbmUoYWVzKHk9YXMubnVtZXJpYyhDaGxSRlUpKSxjb2xvcj0ia2hha2kiKQoKcHJpbnQoc3Rvcm0uMS43LjEzICsgZ2d0aXRsZSgiU3Rvcm0gMS83LzEzIikrbGFicyh4PSJUaW1lIikpCmBgYAoKIyBUcnlpbmcgdG8gbWFrZSB0aGUgUmFpbmZhbGwgcGxvdCBlYXNpZXIgdG8gcmVhZAoKYGBge3J9ClJpdmVyRmxvdzEgPC0gZ2dwbG90KGhpbG9tb2RpZmllZFsxOjEwMCxdLCAgYWVzKHggPSBkYXRlLCB5ID0gYXMubnVtZXJpYyhjbXMpKSkgKyAKICBnZW9tX2xpbmUoKQoKcHJpbnQoUml2ZXJGbG93ICsgZ2d0aXRsZSgiUml2ZXIgRmxvdyIpK2xhYnMoeD0iVGltZSIsIHkgPSAiUml2ZXIgRmxvdyAtIGN1YmljIG1ldGVycyBwZXIgc2Vjb25kIikpCmBgYAo9PT09PT09CmBgYHtyfQpnZXR3ZCgpCiMgd3JpdGUuY3N2KGhpbG9tb2RpZmllZCxmaWxlPSJIaWxvQmF5TkVXMTN0bzE1LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKYGBgCgojIE5FVyBDaGFuZ2UgaW4gUml2ZXIgRmxvdyBDb2x1bW4gCgpgYGB7cn0KIyBhbnkgdmFsdWUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIDEwIGNtcyBpbmRpY2F0ZXMgYSBzdG9ybQpwb3MubmVnIDwtIGFzLm51bWVyaWMoaGlsb21vZGlmaWVkJGNtcykgLSAxMCAKCnN0YXJ0IDwtIHZlY3RvcigpCmVuZCA8LSB2ZWN0b3IoKQoKZm9yKGkgaW4gMTpsZW5ndGgocG9zLm5lZykpewogIGlmKGlzVFJVRShwb3MubmVnW2ldIDwgMCAmJiBwb3MubmVnW2krMV0gPiAwKSl7IAogICAgIyBpZiBnb2VzIGZyb20gKyB0byAtIHRoZW4gdGhpcyBpcyB0aGUgYmVnaW5uaW5nIG9mIGEgc3Rvcm0KICAgIHN0YXJ0W2ldIDwtIGkKICB9ZWxzZSBpZihpc1RSVUUocG9zLm5lZ1tpXSA+IDAgJiYgcG9zLm5lZ1tpKzFdIDwgMCkpewogICAgIyBpZiBnb2VzIGZyb20gLSB0byArIHRoZW4gdGhpcyBpcyB0aGUgZW5kIG9mIHRoZSBzdG9ybQogICAgZW5kW2ldIDwtIGkKICAgIH0KfQpzdGFydDwtc3RhcnRbIWlzLm5hKHN0YXJ0KV0gIyByZW1vdmluZyBOQQpzdGFydApsZW5ndGgoc3RhcnQpICMgbWFrZSBzdXJlIGJvdGggc3RhcnQgYW5kIGVuZCBhcmUgdGhlIHNhbWUgbGVuZ3RoIAoKZW5kPC1lbmRbIWlzLm5hKGVuZCldCmVuZApsZW5ndGgoZW5kKQpgYGAKCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpmb3IoaSBpbiAxOmxlbmd0aChzdGFydCkpewogICMgdGhlIHBvaW50IHN0YXJ0W2ldIGlzIHRoZSBiZWdpbm5pbmcgb2YgYSBzdG9ybQogICMgdGhlIHBvaW50IGVuZFtpXSBpcyB0aGUgZW5kIG9mIHRoZSBzYW1lIHN0b3JtCiAgIyB3ZSBhcmUgYWRkaW5nIDI0IGhvdXJzIHRvIGVhY2ggc3RhcnQgYW5kIGVuZCB0aW1lCiBwIDwtIGdncGxvdChoaWxvbW9kaWZpZWRbKHN0YXJ0W2ldLTI0KTooZW5kW2ldKzI0KSxdLGFlcyh4ID0gZGF0ZSwgeSA9IGFzLm51bWVyaWMoY21zKSkpICsKICBnZW9tX2xpbmUoY29sb3I9ImJsYWNrIikKIHAgPC0gcCArIGdlb21fbGluZShhZXMoeSA9IHJhbmdlMDEoYXMubnVtZXJpYyhDb3JyLk5UVSkpKSwgY29sb3I9ImdyZWVuIikgCiBwIDwtIHAgKyBnZW9tX2xpbmUoYWVzKHk9IHJhbmdlMDEoYXMubnVtZXJpYyhDaGxSRlUpKSksY29sb3I9ImJsdWUiKSAKIHAgPC0gcCArIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkZpcnN0IEF4aXMiLCBzZWMuYXhpcyA9IHNlY19heGlzKHRyYW5zID0gfi4qLjA1LCBuYW1lPSJTZWNvbmQgQXhpcyIpCiAgKSAKICAjIGdlb21fbGluZShhZXMoeSA9IHJhbmdlMDEoYXMubnVtZXJpYyhDb3JyLk5UVSkpKSwgY29sb3I9ImdyZWVuIikgKwogICMgZ2VvbV9saW5lKGFlcyh5PSByYW5nZTAxKGFzLm51bWVyaWMoQ2hsUkZVKSkpLGNvbG9yPSJibHVlIikgKwogICMgZ2VvbV9saW5lKGFlcyh5ID0gcmFuZ2UwMShhcy5udW1lcmljKHNhbHRwcHQpKSksY29sb3I9InJlZCIpICsKICAjIGdlb21fbGluZShhZXMoeSA9IHJhbmdlMDEoYXMubnVtZXJpYyhUZW1wQykpKSxjb2xvcj0icHVycGxlIikgKwogICMgZ2VvbV9saW5lKGFlcyh5ID0gcmFuZ2UwMShhcy5udW1lcmljKERvcGVyKSkpLGNvbG9yPSJvcmFuZ2UiKSsKICAgcCA8LSBwICsgZ2d0aXRsZSgiU3Rvcm1zIikrbGFicyh4PSJUaW1lIikKIHByaW50KHApCn0KCmBgYAoKYGBge3J9CnJhbmdlMDEgPC0gZnVuY3Rpb24oeCwgbmEucm0gPSBUUlVFKSB7CiAgIyB2ZXJzaW9uIDEuMSAoOSBBdWcgMjAxMykKICAoeCAtIG1pbih4LCBuYS5ybSA9IG5hLnJtKSkgLyAobWF4KHgsIG5hLnJtID0gbmEucm0pIC0gbWluKHgsIG5hLnJtID0gbmEucm0pKQp9CmBgYAoKIyB1c2luZyBiYXNlIFIKYGBge3J9CmZvcihpIGluIDE6bGVuZ3RoKHN0YXJ0KSl7CmluZGV4IDwtIGMoKHN0YXJ0W2ldLTI0KTooZW5kW2ldKzI0KSkKCmRhdGUgPC0gYyhoaWxvbW9kaWZpZWQkZGF0ZVtpbmRleF0pCmVuZGRhdGUgPC0gaGlsb21vZGlmaWVkJGRhdGVbZW5kW2ldKzI0XQplbmRjbXMgPC0gYXMubnVtZXJpYyhoaWxvbW9kaWZpZWQkY21zW2VuZFtpXSsyNF0pCmVuZGNobCA8LSByYW5nZTAxKGFzLm51bWVyaWMoaGlsb21vZGlmaWVkJGNtc1tlbmRbaV0rMjRdKSkKZW5kdHVyYiA8LSBhcy5udW1lcmljKGhpbG9tb2RpZmllZCRjbXNbZW5kW2ldKzI0XSkKZW5kc2FsdCA8LSBhcy5udW1lcmljKGhpbG9tb2RpZmllZCRjbXNbZW5kW2ldKzI0XSkKZW5kdGVtcCA8LSBhcy5udW1lcmljKGhpbG9tb2RpZmllZCRjbXNbZW5kW2ldKzI0XSkKZW5kRE8gPC0gYXMubnVtZXJpYyhoaWxvbW9kaWZpZWQkY21zW2VuZFtpXSsyNF0pCgpwYXIobWFyID0gYyg1LCA0LCA0LCA0KSArIDAuMykgIyBBZGRpdGlvbmFsIHNwYWNlIGZvciBzZWNvbmQgeS1heGlzCnBsb3QoeCA9IGRhdGUseSA9IGFzLm51bWVyaWMoaGlsb21vZGlmaWVkJGNtc1tpbmRleF0pLCB0eXBlID0gImwiLGx3ZD0yLCBjb2w9ImJsYWNrIiwgeGxhYj0iVGltZSIpICMgQ3JlYXRlIGZpcnN0IHBsb3QgZm9yIFJpdmVyIEZsb3cKCnBhcihuZXcgPSBUUlVFKSAjIEFkZCBuZXcgcGxvdApwbG90KHggPSBkYXRlICx5ID0gcmFuZ2UwMShhcy5udW1lcmljKGhpbG9tb2RpZmllZCRDaGxSRlVbaW5kZXhdKSksYXhlcyA9IEZBTFNFLCB0eXBlID0gImwiLGx3ZD0yLCBjb2w9ImJsdWUiLCB5bGFiID0gIlRpbWUiKSAgIyBDcmVhdGUgc2Vjb25kIHBsb3Qgd2l0aG91dCBheGVzCmxpbmVzKHggPSBkYXRlICx5ID0gcmFuZ2UwMShhcy5udW1lcmljKGhpbG9tb2RpZmllZCRDb3JyLk5UVVtpbmRleF0pKSwgdHlwZSA9ICJsIixsd2Q9MiwgY29sPSJyZWQiKQpsaW5lcyh4ID0gZGF0ZSAseSA9IHJhbmdlMDEoYXMubnVtZXJpYyhoaWxvbW9kaWZpZWQkc2FsdHBwdFtpbmRleF0pKSwgdHlwZSA9ICJsIixsd2Q9MiwgY29sPSJncmVlbiIpCmxpbmVzKHggPSBkYXRlICx5ID0gcmFuZ2UwMShhcy5udW1lcmljKGhpbG9tb2RpZmllZCRUZW1wQ1tpbmRleF0pKSwgdHlwZSA9ICJsIixsd2Q9MiwgY29sPSJvcmFuZ2UiKQpsaW5lcyh4ID0gZGF0ZSAseSA9IHJhbmdlMDEoYXMubnVtZXJpYyhoaWxvbW9kaWZpZWQkRG9wZXJbaW5kZXhdKSksIHR5cGUgPSAibCIsbHdkPTIsIGNvbD0icHVycGxlIikKYXhpcyhzaWRlID0gNCkgICAjIEFkZCBzZWNvbmQgYXhpcwojbXRleHQoInkyIiwgc2lkZSA9IDQsIGxpbmUgPSAzKSAjIEFkZCBzZWNvbmQgYXhpcyBsYWJlbAoKdGV4dCh4PSBlbmRkYXRlLCB5ID0gZW5kY21zLCBjb2wgPSAiYmxhY2siLCBhZGo9MSwgY2V4PTAuODUsIGxhYmVsPSAiUml2ZXIgRmxvdyIpCnRleHQoeD0gZW5kZGF0ZSwgeSA9IGVuZGNobCwgY29sID0gImJsdWUiLCBhZGo9MSwgY2V4PTAuODUsIGxhYmVsPSAiQ0hMIikKdGV4dCh4PSBlbmRkYXRlLCB5ID0gZW5kdHVyYiwgY29sID0gInJlZCIsIGFkaj0xLCBjZXg9MC44NSwgbGFiZWw9ICJUVVJCIikKdGV4dCh4PSBlbmRkYXRlLCB5ID0gZW5kc2FsdCwgY29sID0gImdyZWVuIiwgYWRqPTEsIGNleD0wLjg1LCBsYWJlbD0gIlNhbGluaXR5IikKdGV4dCh4PSBlbmRkYXRlLCB5ID0gZW5kdGVtcCwgY29sID0gIm9yYW5nZSIsIGFkaj0xLCBjZXg9MC44NSwgbGFiZWw9ICJURU1QIikKdGV4dCh4PSBlbmRkYXRlLCB5ID0gZW5kRE8sIGNvbCA9ICJwdXJwbGUiLCBhZGo9MSwgY2V4PTAuODUsIGxhYmVsPSAiRElTIikKfQpgYGAKIAoKCg==